package com.thread.sync.sync04;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.PriorityBlockingQueue;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.TimeUnit;

import org.junit.Test;

public class MyQueue {

    @Test
    public void test01() {
        ConcurrentLinkedQueue<String> clq = new ConcurrentLinkedQueue<String>();
        //add与offer都是添加元素,在ConcurrentLinkedQueue中没任何区别
        clq.add("a");
        clq.add("b");
        clq.offer("c");
        clq.offer("d");
        System.out.println(clq.poll());//取出头部数据,会删除头部元素
        System.out.println(clq.peek());//取出头部数据,不会删除头部元素
        System.out.println(clq);
    }

    @Test
    public void test02() throws Exception {
        //必须指定队列长度
        ArrayBlockingQueue<String> abq = new ArrayBlockingQueue<String>(2);
        abq.add("a");
        //add :添加元素,如果BlockingQueue可以容纳,则返回true,否则抛异常,支持添加集合
        System.out.println(abq.offer("b"));//容量如果不够,返回false
        //offer: 如果可能的话,添加元素,即如果BlockingQueue可以容纳,则返回true,否则返回false,支持设置超时时间
        //设置超时,如果超过时间就不添加,返回false,
        abq.offer("d", 2, TimeUnit.SECONDS);// 添加的元素,时长,单位
        //put 添加元素,如果BlockQueue没有空间,则调用此方法的线程被阻断直到BlockingQueue里面有空间再继续.
        abq.put("d");//会一直等待
        //poll 取走头部元素,若不能立即取出,则可以等time参数规定的时间,取不到时返回null,支持设置超时时间
        abq.poll();
        abq.poll(2, TimeUnit.SECONDS);//两秒取不到返回null
        //take()  取走头部元素,若BlockingQueue为空,阻断进入等待状态直到Blocking有新的对象被加入为止
        abq.take();
        //取出头部元素,但不删除
        abq.element();
        //drainTo()
        //一次性从BlockingQueue获取所有可用的数据对象（还可以指定获取数据的个数），通过该方法，可以提升获取数据效率；不需要多次分批加锁或释放锁。
        List list = new ArrayList();
        abq.drainTo(list, 2);//将队列中两个元素取到list中，取走后队列中就没有取走的元素
        System.out.println(list); //[a,b]
        System.out.println(abq);  //[]
    }

    @Test
    public void test03() {
        LinkedBlockingQueue lbq = new LinkedBlockingQueue();//可指定容量，也可不指定
        lbq.add("a");
        lbq.add("b");
        lbq.add("c");
        //API与ArrayBlockingQueue相同
        //是否包含
        System.out.println(lbq.contains("a"));
        //移除头部元素或者指定元素  remove("a")
        System.out.println(lbq.remove());
        //转数组
        Object[] array = lbq.toArray();
        //element 取出头部元素，但不删除
        System.out.println(lbq.element());
        System.out.println(lbq.element());
        System.out.println(lbq.element());
    }


    public static void main(String[] args) {
        SynchronousQueue<String> sq = new SynchronousQueue<String>();
        // iterator() 永远返回空，因为里面没东西。
        // peek() 永远返回null
        /**
         * isEmpty()永远是true。
         * remainingCapacity() 永远是0。
         * remove()和removeAll() 永远是false。
         */
        new Thread(() -> {
            try {
                //取出并且remove掉queue里的element（认为是在queue里的。。。），取不到东西他会一直等。
                System.out.println(sq.take());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }).start();
        new Thread(() -> {
            try {
                //offer() 往queue里放一个element后立即返回，
                //如果碰巧这个element被另一个thread取走了，offer方法返回true，认为offer成功；否则返回false
                //true ,上面take线程一直在等,
                ////下面刚offer进去就被拿走了,返回true,如果offer线程先执行,则返回false
                System.out.println(sq.offer("b"));

            } catch (Exception e) {
                e.printStackTrace();
            }

        }).start();
        new Thread(() -> {
            try {
                //往queue放进去一个element以后就一直wait直到有其他thread进来把这个element取走
                sq.put("a");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }).start();
    }

    @Test
    public void test04() throws Exception {
        //队列里元素必须实现Comparable接口,用来决定优先级
        PriorityBlockingQueue<String> pbq = new PriorityBlockingQueue<String>();
        pbq.add("b");
        pbq.add("g");
        pbq.add("a");
        pbq.add("c");
        //获取的时候会根据优先级取元素,插入的时候不会排序,节省性能
        //System.out.println(pbq.take());//a,获取时会排序,按优先级获取
        System.out.println(pbq.toString());//如果前面没有取值,直接syso也不会排序
        Iterator<String> iterator = pbq.iterator();
        while (iterator.hasNext()) {
            System.out.println(iterator.next());
        }
    }

    @Test
    public void test05() {
        PriorityBlockingQueue<Person> pbq = new PriorityBlockingQueue<Person>();
        Person p2 = new Person("姚振", 20);
        Person p1 = new Person("侯征", 24);
        Person p3 = new Person("何毅", 18);
        Person p4 = new Person("李世彪", 22);
        pbq.add(p1);
        pbq.add(p2);
        pbq.add(p3);
        pbq.add(p4);
        System.out.println(pbq);//没有按优先级排序
        try {
            //只要take获取元素就会按照优先级排序,获取一次就全部排好序了,后面就会按优先级迭代
            pbq.take();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //按年龄排好了序
        for (Iterator iterator = pbq.iterator(); iterator.hasNext(); ) {
            Person person = (Person) iterator.next();
            System.out.println(person);
        }
    }

    @Test
    public void test06() {
    }

}
